/*
 *  LLDataNode.h
 *  LID Library
 *
 *  Created by Alexander Trutchenko on 09/11/11.
 *  Copyright 2011 League of Independent Developers. All rights reserved.
 *
 */

#ifndef __LL_DataNode_h__
#define __LL_DataNode_h__

#include <map>
#include <list>
#include <vector>
#include <string>

namespace lidlib {
	
class LLDataNode;

////////////////////////////////////////////////////////
// Types

typedef std::map<std::string, LLDataNode>	    LLDataNodeMap;	
typedef std::list<LLDataNode>				    LLDataNodeList;
typedef std::pair<std::string, LLDataNode>		LLDataNodePair;	


////////////////////////////////////////////////////////
//
/** LLDataNode
 */
//////////////////////////////////////////////////////// 

class LLDataNodeValueBase
{


protected:
	LLDataNodeValueBase() {;}
	
public:
	virtual ~LLDataNodeValueBase() {;}
};

template<typename NodeType>
class LLDataNodeValue : public LLDataNodeValueBase
{
	NodeType*	_pValue;
	
public:
	LLDataNodeValue(NodeType* pValue): LLDataNodeValueBase(), _pValue(pValue) {;}
	LLDataNodeValue(const NodeType& value): _pValue(new NodeType(value)) {;}
	LLDataNodeValue(const LLDataNodeValue& nodeValue)
	{
		delete _pValue;
		_pValue = new NodeType(nodeValue._pValue);
	}

	~LLDataNodeValue() 
	{  
		delete _pValue; 
	} 	
	
	inline NodeType& v() const { return *_pValue; }
    inline NodeType* pv() const { return _pValue; }
};
	
class LLDataNode 
{
	LLDataNodeValueBase* _pValue;
	unsigned int* _pCounter;

private:
	LLDataNode() {;}

public:

	LLDataNode(LLDataNodeValueBase* pValue): _pValue(pValue), _pCounter(new unsigned int(1)) {;}
    LLDataNode(const LLDataNode& node)
	{
		_pCounter = node._pCounter;
		_pValue = node._pValue;
		++(*_pCounter);
	}

	~LLDataNode() 
	{ 
		if (*_pCounter == 1)
		{
			delete _pValue; 
			delete _pCounter; 
		}
		else
			--(*_pCounter);
	} 	

    LLDataNode& operator =(const LLDataNode& node)
    {
 		if (*_pCounter == 1) 
		{
			delete _pCounter; 
			delete _pValue;
		}
		else
			--(*_pCounter);
        _pCounter = node._pCounter;
        _pValue = node._pValue;
        ++(*_pCounter);

        return *this;
    }
	
	inline LLDataNodeValueBase& nv() const { return *_pValue; }
};	
	

////////////////////////////////////////////////////////
// Help template functions

template<typename T>
T& getNodeValue(const LLDataNode& node)
{
    return ((const LLDataNodeValue<T>&)node.nv()).v();
};

template<typename T>
T* getNodeValuePointer(const LLDataNode& node)
{
    return ((const LLDataNodeValue<T>&)node.nv()).pv();
};


template<typename T>
void getNodeMapValue(T& result, const LLDataNodeMap& nodeMap, const std::string& key)
{
    LLDataNodeMap::const_iterator it = nodeMap.find(key);
	if (it != nodeMap.end())
        result = ((const LLDataNodeValue<T>&)it->second.nv()).v();
};

template<typename T>
void setNodeMapValue(const T& value, LLDataNodeMap& nodeMap, const std::string& key)
{
    if(nodeMap.find(key) != nodeMap.end())
        nodeMap.erase(key);
    nodeMap.insert(LLDataNodePair(key, LLDataNode(new LLDataNodeValue<T>(value))));
}



template<typename T>
T* getNodeMapValuePointer(const LLDataNodeMap& nodeMap, const std::string& key)
{
    LLDataNodeMap::const_iterator it = nodeMap.find(key);
    if (it != nodeMap.end())
        return ((const LLDataNodeValue<T>&)it->second.nv()).pv();
    return NULL;
};

template<typename T>
void setNodeMapValuePointer(T* pValue, LLDataNodeMap& nodeMap, const std::string& key)
{
    if(nodeMap.find(key) != nodeMap.end())
        nodeMap.erase(key);
    nodeMap.insert(LLDataNodePair(key, LLDataNode(new LLDataNodeValue<T>(pValue))));
}



}; // end namespace lidlib

#endif // __LL_DataNode_h__
